package com.yupi.springbootinit.handler;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * webSocket长连接处理器
 * @author 穹龙
 * @date 2025/2/12
 */
@Slf4j
public class MyWebSocketHandler extends TextWebSocketHandler {

    /**
     * 根据sessionId存储session
     */
    private static final ConcurrentHashMap<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
    /**
     * 根据用户id存储sessionId
     */
    private static final ConcurrentHashMap<String, String> userSessionMap = new ConcurrentHashMap<>();

    /**
     * 接受前端发送的websocket消息（前端建立连接、主动发送消息、发送心跳都会走此方法）
     *
     * @param session 会话
     * @param message 消息
     */
    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        try {
            log.info("handleTextMessage message = {}", JSONUtil.toJsonStr(message));
            log.info("handleTextMessage session = {}", JSONUtil.toJsonStr(session));
            String sessionId = session.getId();
            if (!sessionMap.containsKey(sessionId)) {
                this.putSessionMap(session);
            }
            JSONObject payload = JSONUtil.parseObj(message.getPayload());
            Object userId = payload.get("userId");
            if (ObjectUtil.isNotNull(userId)) {
                this.putUserSessionMap(sessionId, userId.toString());
            }
        } catch (Exception e) {
            log.error("错误-message = {}, session = {}", JSONUtil.toJsonStr(message), JSONUtil.toJsonStr(session), e);
            sendError(session, e.getMessage());
        }
    }

    /**
     * 新增会话
     *
     * @param session 会话
     */
    public void putSessionMap(WebSocketSession session) {
        sessionMap.put(session.getId(), session);
        sendMessage(session, "连接会话成功");
    }

    /**
     * 新增用户会话关联
     *
     * @param sessionId 会话Id
     * @param userId   用户Id
     */
    public void putUserSessionMap(String sessionId, String userId) {
        log.info("sessionId = {}", sessionId);
        log.info("userId = {}", userId);
        if (!userSessionMap.containsKey(userId)) {
            userSessionMap.put(userId, sessionId);
            WebSocketSession session = sessionMap.get(sessionId);
            sendMessage(session, JSONUtil.toJsonStr("会话绑定用户成功"));
        }
    }

    /**
     * 发送错误信息
     *
     * @param session 会话
     * @param message 消息
     */
    private void sendError(WebSocketSession session, String message) {
        if (sessionMap.containsKey(session.getId())) {
            sendMessage(session, "错误：" + message);
        }
    }

    /**
     * 根据用户Id发送消息
     *
     * @param userId  用户Id
     * @param message 消息
     */
    public void sendMessageByUserId(String userId, Object message) {
        log.info("message = {}", JSONUtil.toJsonStr(message));
        log.info("userSessionMap = {}", JSONUtil.toJsonStr(userSessionMap));
        log.info("sessionMap = {}", JSONUtil.toJsonStr(sessionMap));
        if (userSessionMap.containsKey(userId)) {
            String sessionId = userSessionMap.get(userId);
            if (sessionMap.containsKey(sessionId)) {
                WebSocketSession session = sessionMap.get(sessionId);
                sendMessage(session, JSONUtil.toJsonStr(message));
            }
        }
    }

    /**
     * 发送消息
     *
     * @param session 会话
     * @param message 消息
     */
    private synchronized void sendMessage(WebSocketSession session, String message) {
        try {
            session.sendMessage(new TextMessage(message));
        } catch (IOException e) {
            log.error("发送消息异常", e);
        }
    }

    /**
     * 当前端断开会话后删除会话
     *
     * @param session 会话
     * @param status  断开状态
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        String sessionId = session.getId();
        log.info("sessionId = {}, status = {}", sessionId, status);
        sessionMap.remove(sessionId);
        for (Map.Entry<String, String> entry : userSessionMap.entrySet()) {
            String value = entry.getValue();
            if (sessionId.equals(value)) {
                userSessionMap.remove(entry.getKey());
            }
        }
    }
}
